NPC Cloud and Lightning (Godot Timer)
Cloud NPC
Playerとは直接衝突しない
下にBunnyがいるとLightningを落とす
数秒ごとに1回落とす
左右に漂う
drift = 漂流する
Lightning NPC
真っ直ぐ落ちる
地形かBunnyに当たると消える
画面から消えたら消える。
Bunnyにあたったらダメージを与える
AnimationPlayerのAutoplay
AudioStreamPlayerやAnimatedSpriteと異なり、
インスペクタにplaying や autoplay プロパティがない
代わりに、下のタブのアニメーションタイムラインで、
編集ボタンの横にある 読み込み後、自動再生をオンにしておく
RayCast2Dで下にいるプレイヤーを検知
現実世界で言うところの、「自動ドアの赤外線センサー」
光線のような検出エリア
自分自身は当たり判定を持たない。
Collision Layerがなくて Maskだけがある。
そのため、on_*_entered() や on_*_exited()というシグナルはなく、
スクリプトの_process()の中で、手動で検知のコードを書く
RayCast2D.
is_colliding()
あたっているかどうかをboolで返す
かんたんに検出するならこれ
衝突相手を判別できないので、Maskをしっかり設定して特定の相手にしか当たらないようにする
get_collider() : 最初にあたったオブジェクトを返す
一番最初にあたったObjectを返す
当たらなかったらnullを返す
Lightningを生成 + クールタイムを作る
GDScriptで新しいNodeをインスタンス化するには、
1. .tscnリソースをロードする
2. Resource.instance()でノードをインスタンス化する
3. Node.add_child()
これを、RayCast2Dがプレイヤーを捉えたときに行えばよいが、
そのままだとあたり判定が残っているので何度もぶつかると多重生成される。
Timer Node のsignalである、timeout()をスクリプトに接続して
指定時間まで、Lightningの生成ができないようにする
code: Cloud.py
extends Node2D
var timeout = false
func _process(delta):
if $Sprite/RayCast2D.is_colliding():
fire()
func fire():
if not timeout:
$Sprite/RayCast2D.add_child(load("res://NPCs/Lightning.tscn").instance())
$Timer.start()
timeout = true
func _on_Timer_timeout():
timeout = false
Lightning
https://gyazo.com/5e01b1a581c90b523e38df524824e309
VisibilityNotifier2D : 画面から消えたら通知するNode
2DNodeの一種
signalの中に、
screen_entered()
screen_exited()
という物があり、画面から出たり入ったりしたときにコールバックを実行できる。
Lightningをインスタンス化 & treeに加える
親のローカル座標ではなく、グローバル座標で制御する
Nodeを見えるようにするには、scene_treeのどれかのNodeにnode.add_childe(instance)
する必要がある。
Cloud/Raycast2D の子供にしたい
しかし、Cloudが動くと発射されたLighningも動いてしまうので、
Lightning.set_as_toplevel(true) とすることで
親の位置を継承せずに動くことができる
code: Lightning.py
extends Node2D
const SPEED = 200
func _ready():
set_as_toplevel(true) # 親から位置を受け継がない
# Node.get_parent() : 親Nodeを取得
# Node.global_position : グローバル座標プロパティ Vector2D
# set, get できる
global_position = get_parent().global_position
func _process(delta):
position.y += SPEED * delta
manage_collision()
func manage_collision():
var collider = $Area2D.get_overlapping_bodies() # 重なっているPhysicsBody2D (とそれを継承したオブジェクト) を Listで返す。
for object in collider:
if object.name == "Player": # あたったのがPlayerのとき
print("ouch")
get_tree().call_group("GameState", "hurt")
queue_free() # あたったのがPlayerであろうがTerrainであろうが、何かと重なったら消滅
# 画面から消えたら見えなくなる(VisiblityNotifier2D)
func _on_VisibilityNotifier2D_screen_exited():
queue_free()
まとめ
Sceneをインスタンス化する方法
Nodeがエンジン機能を頼りとするクラスなのに対し
Resourceはデータの格納に重要なデータ型
ディスクに保存したり、読み込んだりするものはすべてResource型
ファイルに保存されたSceneは.tscnファイルなのでリソース
load()関数で読み込んで、Resource.instance()メソッドでNodeインスタンスを作成
add_child()メソッドでシーンツリーに配置すると見えるようになる。
code: instantiate.py
resource = load("res://***.tscn") # TSCN Resourceオブジェクト
node = resource.instance( ) # Nodeオブジェクト
parent.add_child(node) # シーンツリーに配置
RayCast2D
光線のような検出範囲
on_enterのようなシグナルはないので、_process()などで毎フレーム検出処理を書く
is_colliding()やget_collider()メソッドを使う
VisibilityNotifier2D
画面から出たり入ったりしたらsignalを出す
Timer
Timer.start(sec) で開始
timeout()でsinalを出す
n秒後にコールバックを実行できる